/***************************************************
> Copyright (C) 2025 ==ASD== All rights reserved.
> File Name: hw4.c
> Author: asd
> Mail:3319941451@qq.com 
> Created Time: 2025年01月03日 星期五 17时06分51秒
***************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <mysql/mysql.h>
#include <sys/mman.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <semaphore.h>
#include <pthread.h>

// MySQL数据库连接相关变量
MYSQL *conn;
// 共享内存相关变量
void *shared_memory;
int shared_memory_fd;
// 信号量相关变量
sem_t sem1;
sem_t sem2;

pthread_mutex_t mutex;

// 定义结构体存储数据包信息
typedef struct Packet {
    int sequence_number;
    char data[1000];
    char file_path[20];
    char authorization[20];
} Packet;

// 函数声明
void read_data_from_file(char *file_path,Packet *packet);
void add_data_info(Packet *packet);
void write_packet_to_shared_memory(Packet *packet);

int main() {
    // 连接到MySQL数据库
    conn = mysql_init(NULL);
    if (conn == NULL) {
        fprintf(stderr, "mysql_init() failed\n");
        exit(-1);
    }
    if (mysql_real_connect(conn, "localhost", "root", "123456", "data", 0, NULL, 0) == NULL) {
        fprintf(stderr, "mysql_real_connect() failed: %s\n", mysql_error(conn));
        exit(-1);
    }

    // 创建共享内存用于存储数据包
    shared_memory_fd = shmget(0, sizeof(Packet), IPC_CREAT | 0666);
    if (shared_memory_fd == -1) {
        perror("shmget failed");
        exit(-1);
    }
    shared_memory = mmap(NULL, sizeof(Packet), PROT_READ | PROT_WRITE, MAP_SHARED, shared_memory_fd, 0);
    if (shared_memory == MAP_FAILED) {
        perror("mmap failed");
        exit(-1);
    }

    // 创建并初始化信号量
    // 初始化信号量 sem1，初始值为0
    if (sem_init(&sem1, 0, 0) == -1) {
        perror("sem_init for sem1 failed");
        exit(-1);
    }
    // 初始化信号量 sem2，初始值为0
    if (sem_init(&sem2, 0, 1) == -1) {
        perror("sem_init for sem2 failed");
        sem_destroy(&sem1);
        exit(-1);
    }
	int ret = 0;
	ret = pthread_mutex_init(&mutex,NULL);
	if(ret != 0)
	{
		perror("pthread_mutex_init");
		exit(-1);
	}

    // 读取文件数据并打包
    Packet packet;
    add_data_info(&packet);

    // 将数据包写入共享内存
    write_packet_to_shared_memory(&packet);

    // 释放共享内存
    if (munmap(shared_memory, sizeof(Packet)) == -1) {
        perror("munmap failed");
    }
    if (shmctl(shared_memory_fd, IPC_RMID, NULL) == -1) {
        perror("shmctl failed");
    }

    // 销毁信号量
    // 销毁信号量 sem1
    if (sem_destroy(&sem1) == -1) {
        perror("sem_destroy for sem1 failed");
    }
    // 销毁信号量 sem2
    if (sem_destroy(&sem2) == -1) {
        perror("sem_destroy for sem2 failed");
    }

    // 关闭MySQL连接
    mysql_close(conn);
    return 0;
}
void read_data_from_textfile(char *file_path,Packet *packet) {
   void read_data_from_file(char *file_path,Packet *packet) {
    int file_fd = open(file_path, O_REONLY);
    if (file_fd == -1) 
	{
        perror("open file failed");
        return;
    }
    // 读取文件内容到数据包的数据部分（这里简单假设文件内容不超过数据包数据大小）
    int bytes_read = read(file_fd, packet->data, sizeof(packet->data));
    if (bytes_read == -1) 
	{
        perror("read");
        close(file_fd);
        return;
    }
    close(file_fd);
}

}
void read_data_from_otherfile(char *file_path,Packet *packet) {
    FILE *file_fp = fopen(file_path, "rb+");
    if (file_fp == -1) 
	{
        perror("fopen");
        return;
    }
    // 读取文件内容到数据包的数据部分（这里简单假设文件内容不超过数据包数据大小）
    size_t bytes_read = fread(packet->data, sizeof(packet->data),1,file_fp);
    if (bytes_read == -1) 
	{
        perror("read");
        fclose(file_fp);
        return;
    }
    fclose(file_fp);
}

void add_data_info(Packet *packet) {
    // 假设从数据库中查询授权信息并添加到数据包
    int ret;
    mysql_query(conn, "SET NAMES utf8"); // 设置中文字符集
    char sql_buf[128] = "select * from data";
    ret = mysql_query(conn, sql_buf); // 执行sql语句
    if (ret!= 0) {
        printf("mysql query failed\n");
    }
    MYSQL_RES *res;
    res = mysql_store_result(conn); // 存储查询结果
    if (res == NULL) {
        printf("存储结果失败\n");
    }
    unsigned int count;
    count = mysql_field_count(conn);
    unsigned int fields;
    fields = mysql_num_fields(res);
    MYSQL_ROW row; 
    row =  mysql_fetch_row(res);
    if(row!= NULL) { // 获取一行结果
        packet->sequence_number = atoi(row[0]);
		strncpy(packet->file_type, row[1], sizeof(packet->file_type) - 1);
        strncpy(packet->file_path, row[2], sizeof(packet->file_path) - 1);
        strncpy(packet->authorization, row[3], sizeof(packet->authorization) - 1);
		if(!strcmp(packet->file_type,"text"))
		{
			read_data_from_textfile(packet->file_path, packet);
		}else
		{
			read_data_from_otherfile(packet->file_path, packet);
		}
    }
}

void write_packet_to_shared_memory(Packet *packet) {
    // 等待 sem1 信号量
    if (sem_wait(&sem1) == -1) {
        perror("sem_wait for sem1 failed");
        return;
    }
    // 获取互斥锁（
    pthread_mutex_lock(&mutex);
    // 将数据包写入共享内存
    memcpy(shared_memory, packet, sizeof(Packet));
    // 释放互斥锁
    pthread_mutex_unlock(&mutex);
    // 发送 sem2 信号量
    if (sem_post(&sem2) == -1) {
        perror("sem_post for sem2 failed");
    }
}